import 'dart:convert';
import 'dart:io';

import 'package:flutter_architecture/src/api/open_weather_api.dart';
import 'package:flutter_architecture/src/constants/api_keys.default.dart';
import 'package:flutter_architecture/src/features/weather/data/api_exception.dart';
import 'package:flutter_architecture/src/features/weather/domain/forecast/forecast.dart';
import 'package:flutter_architecture/src/utils/log.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:http/http.dart' as http;

import '../domain/weather/weather.dart';

class WeatherRepository {
  final OpenWeatherApi api;
  final http.Client client;

  WeatherRepository({required this.api, required this.client});

  Future<Forecast> getForecast({required String city}) => _getData(
      uri: api.forecast(city), builder: (data) => Forecast.fromJson(data));

  Future<Weather> getWeather({required String city}) => _getData(
      uri: api.weather(city), builder: (data) => Weather.fromJson(data));

  Future<T> _getData<T>(
      {required Uri uri, required T Function(dynamic data) builder}) async {
    try {
      final response = await client.get(uri);
      switch (response.statusCode) {
        case 200:
          Log.d('response.body: ${response.body}');
          final data = json.decode(response.body);
          return builder(data);
        case 401:
          throw InvalidApiKeyException();
        case 404:
          throw CityNotFoundException();
        default:
          throw UnknownException();
      }
    } on SocketException catch (_) {
      throw NoInternetConnectionException();
    }
  }
}

/// Providers used by rest of the app
final weatherRepositoryProvider = Provider<WeatherRepository>((ref) {
  const apiKey = String.fromEnvironment('API_KEY',
      defaultValue: ApiKeys.openWeatherApiKey);
  return WeatherRepository(api: OpenWeatherApi(apiKey), client: http.Client());
});
